﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OptiGear1
{
    class Gearset : ICloneable
    {
        public double weight;
        public int hit;
        public int originalhit; //unmodified version for returning hit total at end of optmisation
        public int[] partIDs; //stores wowheadID
        public string[] partIDString; //for wowheadID = gem IDs + ench IDs.
        public int t7count;
        public int t8count;
        public int t9count;
        public int t10count;

        public double metaweight;
        public double metaactiveweight; //set if meta is active
        public int metaslotreq;
        public int metaredreq;
        public int metabluereq;
        public int metayellowreq;

       
        public Gearset()
        {
            weight = 0.0;
            metaweight = 0.0;
            metaactiveweight = 0.0;
            metaslotreq = 0;
            metaredreq = 0;
            metabluereq = 0;
            metayellowreq = 0;
            hit = 0;
            originalhit = 0;
            partIDs = new int[Utils.bodyparts.Length];
            partIDString = new string[Utils.bodyparts.Length];
        }

        public object Clone()
        {
            //return this.MemberwiseClone(); doesn't clone the array...
            Gearset g = new Gearset();
            g.weight = this.weight;
            g.hit = this.hit;
            g.originalhit = this.originalhit;
            g.t7count = this.t7count;
            g.t8count = this.t8count;
            g.t9count = this.t9count;
            g.t10count = this.t10count;
            g.metaweight = this.metaweight;
            g.metaactiveweight = this.metaactiveweight;
            g.metaslotreq = this.metaslotreq;
            g.metaredreq = this.metaredreq;
            g.metabluereq = this.metabluereq;
            g.metayellowreq = this.metayellowreq;
            for (int i = 0; i < partIDs.Length; i++)
            {
                g.partIDs[i] = this.partIDs[i];
            }
            for (int i = 0; i < partIDString.Length; i++)
            {
                g.partIDString[i] = this.partIDString[i];
            }
            return g;
        }
        
        public void AddItem(WowItem item)
        {
            //meta gems have zero weight until activated
            if (item.bodypart == "Meta")
            {
                metaweight = item.weight;
                metaredreq = item.metaredreq;
                metabluereq = item.metabluereq;
                metayellowreq = item.metayellowreq;
            }

            if ((metaredreq + metabluereq + metayellowreq) > 0)
            {
                for (int i = 0; i < item.Gems.Count; i++)
                {
                    if (item.Gems[i].red > 0 && metaredreq > 0)
                        metaredreq--;
                    if (item.Gems[i].blue > 0 && metabluereq > 0)
                        metabluereq--;
                    if (item.Gems[i].yellow > 0 && metayellowreq > 0)
                        metayellowreq--;
                }
            }
            else
            {
                metaactiveweight = metaweight; //meta is active
            }

            if (item.bodypart != "Meta")
            {
                if (metaweight > 0 && item.bodypart == Utils.bodyparts[Utils.HEAD] && item.metasockets == 0)
                { //prevents a non-meta helm having a meta gem
                    weight -= 10000;
                }

                hit += item.hit;
                originalhit += item.hit;
                weight += item.weight;
            }
            if (item.t7 > 0 && t7count < 4)
                t7count++;
            if (item.t8 > 0 && t8count < 4)
                t8count++;
            if (item.t9 > 0 && t9count < 4)
                t9count++;
            if (item.t10 > 0 && t10count < 4)
                t10count++;

            for (int i = 0; i < Utils.bodyparts.Length; i++)
            {
                if (Utils.bodyparts[i] == item.bodypart && partIDs[i] ==0)
                {
                    partIDs[i] = item.wowheadid;
                    partIDString[i] = item.wowheadid.ToString();
                    for (int j = 0; j < item.Gems.Count; j++)
                    {
                        partIDString[i] += "_" + item.Gems[j].wowheadid;
                    }
                    return;
                }

            }
        }

        public double GetModifiedWeight(double t7_2pc, double t7_4pc, double t8_2pc, double t8_4pc, double t9_2pc, double t9_4pc, double t10_2pc, double t10_4pc, double hitTarget, double lostHitWeight)
        {
            double gearweight = weight;

            if (metaredreq + metabluereq + metayellowreq == 0)
            {
                gearweight += metaweight;
            }

            if (t7count >= 2)
                gearweight += t7_2pc;
            if (t7count >= 4)
                gearweight += t7_4pc;
            if (t8count >= 2)
                gearweight += t8_2pc;
            if (t8count >= 4)
                gearweight += t8_4pc;
            if (t9count >= 2)
                gearweight += t9_2pc;
            if (t9count >= 4)
                gearweight += t9_4pc;
            if (t10count >= 2)
                gearweight += t10_2pc;
            if (t10count >= 4)
                gearweight += t10_4pc;

            if (hit < hitTarget)
                gearweight -= (hitTarget - hit) * lostHitWeight;

            return gearweight;
        }
    }

    class GearsetComparer : IComparer<Gearset>
    {
        public int Compare(Gearset gs1, Gearset gs2)
        {
            if (gs1.hit == gs2.hit)
                return gs2.weight.CompareTo(gs1.weight);
            else
                return gs2.hit.CompareTo(gs1.hit);
        }
    }

    class GearsetHitTargetComparer : IComparer<Gearset>
    {
        private int hitTarget;
        private double lostHitWeight;
        private double t7_2pc;
        private double t7_4pc;
        private double t8_2pc;
        private double t8_4pc;
        private double t9_2pc;
        private double t9_4pc;
        private double t10_2pc;
        private double t10_4pc;

        public GearsetHitTargetComparer(int hitTarget, double lostHitWeight, double t7_2pc, double t7_4pc, double t8_2pc, double t8_4pc, double t9_2pc, double t9_4pc, double t10_2pc, double t10_4pc)
        {
            this.hitTarget = hitTarget;
            this.lostHitWeight = lostHitWeight;
            this.t7_2pc = t7_2pc;
            this.t7_4pc = t7_4pc;
            this.t8_2pc = t8_2pc;
            this.t8_4pc = t8_4pc;
            this.t9_2pc = t9_2pc;
            this.t9_4pc = t9_4pc;
            this.t10_2pc = t10_2pc;
            this.t10_4pc = t10_4pc;
        }

        public int Compare(Gearset gs1, Gearset gs2)
        {
            double gs1weight = gs1.weight;
            double gs2weight = gs2.weight;

            if (gs1.metabluereq + gs1.metaredreq + gs1.metayellowreq == 0)
            {
                gs1weight += gs1.metaweight;
            }
            if (gs2.metabluereq + gs2.metaredreq + gs2.metayellowreq == 0)
            {
                gs2weight += gs2.metaweight;
            }

            if (gs1.t7count >= 2)
                gs1weight += t7_2pc;

            if (gs1.t7count >= 4)
                gs1weight += t7_4pc;

            if (gs1.t8count >= 2)
                gs1weight += t8_2pc;

            if (gs1.t8count >= 4)
                gs1weight += t8_4pc;

            if (gs1.t9count >= 2)
                gs1weight += t9_2pc;

            if (gs1.t9count >= 4)
                gs1weight += t9_4pc;

            if (gs1.t10count >= 2)
                gs1weight += t10_2pc;

            if (gs1.t10count >= 4)
                gs1weight += t10_4pc;



            if (gs2.t7count >= 2)
                gs2weight += t7_2pc;

            if (gs2.t7count >= 4)
                gs2weight += t7_4pc;

            if (gs2.t8count >= 2)
                gs2weight += t8_2pc;

            if (gs2.t8count >= 4)
                gs2weight += t8_4pc;

            if (gs2.t9count >= 2)
                gs2weight += t9_2pc;

            if (gs2.t9count >= 4)
                gs2weight += t9_4pc;

            if (gs2.t10count >= 2)
                gs2weight += t10_2pc;

            if (gs2.t10count >= 4)
                gs2weight += t10_4pc;

            if (gs1.hit < hitTarget)
                gs1weight -= (hitTarget - gs1.hit) * lostHitWeight;

            if (gs2.hit < hitTarget)
                gs2weight -= (hitTarget - gs2.hit) * lostHitWeight;

            //check
            //todo, if matches simplify code
            double gs1weight_x = gs1.GetModifiedWeight(t7_2pc, t7_4pc, t8_2pc, t8_4pc, t9_2pc, t9_4pc, t10_2pc, t10_4pc, hitTarget, lostHitWeight);
            double gs2weight_x = gs2.GetModifiedWeight(t7_2pc, t7_4pc, t8_2pc, t8_4pc, t9_2pc, t9_4pc, t10_2pc, t10_4pc, hitTarget, lostHitWeight);

            if (gs1weight != gs1weight_x || gs2weight != gs2weight_x)
            {
                //something went wrong
            }
            
            return gs2weight.CompareTo(gs1weight);
        }
    }
}
